#include "cropWithInput.h"

namespace sp::Image::Crop{

void registe_cropWithInput(){
    cropWithInput::registe();
}

cropWithInput::cropWithInput(std::vector<std::string> v){
    assert(v.size() == 1);
    name = "cropWithInput";
    class_name = "Image-Crop-cropWithInput";
    cropWay = std::stoi(v[0]);
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({MAT,RECT},MAT));
}

cropWithInput::cropWithInput(int cropWay){
    name = "cropWithInput";
    class_name = "Image-Crop-cropWithInput";
    this->cropWay = cropWay;
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({MAT,RECT},MAT));
}

cropWithInput::cropWithInput(){
    name = "cropWithInput";
    class_name = "Image-Crop-cropWithInput";
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({MAT,RECT},MAT));
}

cropWithInput::~cropWithInput(){

}

void cropWithInput::registe(){
    Function::Register("Image-Crop-cropWithInput", createObject);
    Function::Register("Image-Crop-cropWithInput", createObject2);
}

Function* cropWithInput::createObject(std::vector<std::string> params){
    return new cropWithInput(params);
}

Function* cropWithInput::createObject2(){
    return new cropWithInput();
}

void cropWithInput::start(){

}

bool cropWithInput::waitForResource(){
    return true;
}

void cropWithInput::process(std::vector<std::vector<Data*>>& data_input, std::vector<Data*>& data_output){
    assert(batch_size != 0);
    assert(data_input.size() <= batch_size);
    assert(data_input[0].size() == 2);
    for(int i = 0; i < data_input.size(); i++){
        if(data_input[i][0] == DATA_END)
            break;
        // 从接收到的data构建cv::Mat src
        Data* img = data_input[i][0];
        short app_id = img->getAppId();
        short flow_id = img->getFlowId();
        short request_id = img->getRequestId();
        cv::Mat* src = new cv::Mat(img->context.mat.rows, img->context.mat.cols, CV_8UC3); 
        src->data = img->context.mat.data;
        src->datastart = img->context.mat.data;
        src->dataend = img->context.mat.data + img->context.mat.rows*img->context.mat.cols*img->context.mat.channels;
        src->datalimit = src->dataend;
        // 从接收到的data中构建得到所有的cv::Rect，并进行裁剪。
        Data* d = data_input[i][1]->next;
        // 如果当前图片没有矩形框，传递一个空Data，Empty
        if(d == nullptr && cropWay == 0){
            char* ptr = executor->malloc(Data_Memory);
            Data* data = new (ptr)Data(app_id, flow_id, request_id, EMPTY);
            data_output.push_back(data);
        }else{
            while(d){
                // 得到相关参数
                int width, height, x, y;
                if(cropWay == 0){
                    width = d->context.rect.width*(src->cols);
                    height = d->context.rect.height*(src->rows);
                    x = d->context.rect.x*(src->cols);
                    y = d->context.rect.y*(src->rows);
                }else if(cropWay == 1){
                    width = d->context.rect.width;
                    height = d->context.rect.height;
                    x = d->context.rect.x;
                    y = d->context.rect.y;
                }else{
                    assert(false);
                }
                // 边界检测
                if(x < 0)
                    x = 0;
                if(y < 0)
                    y = 0;
                if(x+width > src->cols)
                    width = src->cols - x;
                if(y+height > src->rows)
                    height = src->rows - y;
                // 新建一个dst的MAT放置crop后的图片
                char* mat_data_ptr = executor->malloc(width, height);
                cv::Mat* dst = new cv::Mat(height, width, CV_8UC3);
                dst->data = (uchar*)mat_data_ptr;
                dst->datastart = dst->data;
                dst->dataend = dst->datastart + height*width*3;
                dst->datalimit = dst->dataend;
                // crop
                // cv::imwrite("./images/before_crop" + std::to_string(cropWay) + "_" + std::to_string(cnt) + ".png", *src);
                cv::Mat crop_img = (*src)(cv::Range(y, y+height), cv::Range(x, x+width));
                *dst += crop_img;
                // 保存图片
                // cv::imwrite("./images/after_crop" + std::to_string(cropWay) + "_" + std::to_string(cnt) + ".png", *dst);
                // 裁剪后的图片存入Data中
                char* ptr = executor->malloc(Data_Memory);
                Data* data = new (ptr)Data(app_id, flow_id, request_id, dst->channels(), dst->rows, dst->cols, dst->data);
                data_output.push_back(data);
                // 下一个Rect
                d = d->next;
                cnt++;
            }
        }
        // 释放空间
        if(img->subRefCount() == 0){
            assert(img->type == MAT);
            executor->free((char*)(img->context.mat.data));
            executor->free((char*)(img));
        }
        if(data_input[i][1]->subRefCount() == 0){
            Data* q = data_input[i][1]->next;
            Data* p = data_input[i][1];
            while(q){
                executor->free((char*)(p));
                p = q;
                q = q->next;
            }
            executor->free((char*)(p));
        }
    }
}

bool cropWithInput::releaseResource(){
    return true;
}

void cropWithInput::finish(){

}

void cropWithInput::copy(Function* other){
    Function::defaultCopy(other);
    cropWithInput* oth = dynamic_cast<cropWithInput*>(other);
    this->cropWay = oth->cropWay;
}

};